﻿////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  © 2012 Stanislav S. Yarmonov.
//
//  TODO:LICENSE
//     
////////////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;

namespace Pandora.Development.Parser
{
    public static class Parsers
    {
        public static Parse<TToken, TToken> Token<TToken>(Predicate<TToken> predicate)
        {
            //TODO:predicate != null

            return input =>
            {
                if (input.CanRead)
                {
                    if (predicate(input.Current))
                    {
                        return input.CreateSuccess<TToken>(input.Current, true);
                    }

                    //TODO:decode non visible tokens (\0x20, \0x13).
                    return input.CreateFailure<TToken>(ParseError.Format("Unexpected token [{0}]", input.Current));
                }

                return input.CreateFailure<TToken>(ParseError.String("Unexpected end of input"));
            };
        }

        public static Parse<TToken, IEnumerable<TToken>> Tokens<TToken>(IEnumerable<TToken> tokens)
            where TToken : IEquatable<TToken>
        {
            //TODO:tokens != null

            return input =>
            {
                IParseInput<TToken> remains = input;
                IEnumerator<TToken> enumerator = tokens.GetEnumerator();

                foreach (TToken token in tokens)
                {
                    IParseSuccess<TToken, TToken> success = Parsers.Token<TToken>(token)(remains).AsSuccess();

                    if (success == null)
                    {
                        return input.CreateFailure<IEnumerable<TToken>>(ParseError.String("Sequence failed"));
                    }

                    remains = success.Remains;
                }

                return remains.CreateSuccess(tokens);
            };
        }

        public static Parse<TToken, TToken> Token<TToken>(TToken value)
            where TToken : IEquatable<TToken>
        {
            return Parsers.Token<TToken>(token => token.Equals(value)); //TODO:nulls?
        }

        public static Parse<TToken, TToken> Any<TToken>()
        {
            return Parsers.Token<TToken>(token => true);
        }
    }
}
